package org.angelica.aliyun.manager;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.auth.sts.AssumeRoleRequest;
import com.aliyuncs.auth.sts.AssumeRoleResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.http.ProtocolType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import org.angelica.aliyun.entity.StsRole;
import org.angelica.aliyun.entity.StsToken;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * 阿里云临时访问凭证服务
 * @author aizhimin
 */
public class StsManager {

    private static final Logger logger = LoggerFactory.getLogger(StsManager.class);

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    private DefaultAcsClient client;

    public StsManager(String endpoint,String accessKeyId,String accessKeySecret){
        // 添加endpoint（直接使用STS endpoint，前两个参数留空，无需添加region ID）
        DefaultProfile.addEndpoint( "", "Sts", endpoint);
        // 构造default profile（参数留空，无需添加region ID）
        IClientProfile profile = DefaultProfile.getProfile("", accessKeyId, accessKeySecret);
        // 用profile构造client
        client = new DefaultAcsClient(profile);
    }

    /**
     * 根据角色获取临时凭证
     * @param stsRole
     * @return
     */
    public StsToken getStsToken(StsRole stsRole){
        try {
            final AssumeRoleRequest request = new AssumeRoleRequest();
            request.setSysMethod(MethodType.POST);
            request.setSysProtocol(ProtocolType.HTTPS);
            request.setRoleArn(stsRole.getRoleArn());
            request.setRoleSessionName(stsRole.getRoleSessionName());
            request.setPolicy(stsRole.getPolicy());

            final AssumeRoleResponse response = client.getAcsResponse(request);
            AssumeRoleResponse.Credentials credentials = response.getCredentials();

            StsToken stsToken = new StsToken(credentials.getAccessKeyId(),
                    credentials.getAccessKeySecret(),
                    credentials.getSecurityToken(),
                    credentials.getExpiration());

            return stsToken;
        } catch (ClientException e) {
            logger.error("Aliyun Error code:"+e.getErrCode()+",message:"+e.getErrMsg());
        }
        return null;
    }

    /**
     * 获取表格存储管理凭证
     * @return
     */
    public StsToken getTableStoreStsToken(){
        try {
            StsRole stsRole = StsRole.getTablestoreManageRole();
            //从缓存中获取ststoken
            String stsJson = stringRedisTemplate.opsForValue().get("tb_sts:"+stsRole.getRoleSessionName());
            if(stsJson != null){
                return JSON.parseObject(stsJson, new TypeReference<StsToken>() {});
            }

            StsToken stsToken = getStsToken(stsRole);

            //设置到缓存中，并设置过期时间
            String expiration = stsToken.getExpiration();
            expiration = expiration.replace("Z"," UTC");
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss Z");
            Date expirationDate = format.parse(expiration);
            long expiredTime = expirationDate.getTime() - System.currentTimeMillis() - 1000;
            stringRedisTemplate.opsForValue().set("tb_sts:"+stsRole.getRoleSessionName(),
                    JSON.toJSONString(stsToken), expiredTime, TimeUnit.MILLISECONDS);
            return stsToken;
        } catch (ParseException e) {
            logger.error(e.getMessage());
        }
        return null;
    }

    /**
     * 获取对象存储管理凭证
     * @return
     */
    public StsToken getOssStsToken(){
        try {
            StsRole stsRole = StsRole.getOssManageRole();
            //从缓存中获取ststoken
            String stsJson = stringRedisTemplate.opsForValue().get("oss_sts:"+stsRole.getRoleSessionName());
            if(stsJson != null){
                return JSON.parseObject(stsJson, new TypeReference<StsToken>() {});
            }

            StsToken stsToken = getStsToken(stsRole);

            //设置到缓存中，并设置过期时间
            String expiration = stsToken.getExpiration();
            expiration = expiration.replace("Z"," UTC");
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss Z");
            Date expirationDate = format.parse(expiration);
            long expiredTime = expirationDate.getTime() - System.currentTimeMillis() - 1000;
            stringRedisTemplate.opsForValue().set("oss_sts:"+stsRole.getRoleSessionName(),
                    JSON.toJSONString(stsToken), expiredTime, TimeUnit.MILLISECONDS);
            return stsToken;
        } catch (ParseException e) {
            logger.error(e.getMessage());
        }
        return null;
    }

    /**
     * 获取智能媒体管理凭证
     * @return
     */
    public StsToken getImmStsToken(){
        try {
            StsRole stsRole = StsRole.getImmManageRole();
            //从缓存中获取ststoken
            String stsJson = stringRedisTemplate.opsForValue().get("imm_sts:"+stsRole.getRoleSessionName());
            if(stsJson != null){
                return JSON.parseObject(stsJson, new TypeReference<StsToken>() {});
            }

            StsToken stsToken = getStsToken(stsRole);

            //设置到缓存中，并设置过期时间
            String expiration = stsToken.getExpiration();
            expiration = expiration.replace("Z"," UTC");
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss Z");
            Date expirationDate = format.parse(expiration);
            long expiredTime = expirationDate.getTime() - System.currentTimeMillis() - 1000;
            stringRedisTemplate.opsForValue().set("imm_sts:"+stsRole.getRoleSessionName(),
                    JSON.toJSONString(stsToken), expiredTime, TimeUnit.MILLISECONDS);
            return stsToken;
        } catch (ParseException e) {
            logger.error(e.getMessage());
        }
        return null;
    }

    /**
     * 获取日志服务管理凭证
     * @return
     */
    public StsToken getLogStsToken(){
        try {
            StsRole stsRole = StsRole.getLogManageRole();
            //从缓存中获取ststoken
            String stsJson = stringRedisTemplate.opsForValue().get("log_sts:"+stsRole.getRoleSessionName());
            if(stsJson != null){
                return JSON.parseObject(stsJson, new TypeReference<StsToken>() {});
            }

            StsToken stsToken = getStsToken(stsRole);

            //设置到缓存中，并设置过期时间
            String expiration = stsToken.getExpiration();
            expiration = expiration.replace("Z"," UTC");
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss Z");
            Date expirationDate = format.parse(expiration);
            long expiredTime = expirationDate.getTime() - System.currentTimeMillis() - 1000;
            stringRedisTemplate.opsForValue().set("log_sts:"+stsRole.getRoleSessionName(),
                    JSON.toJSONString(stsToken), expiredTime, TimeUnit.MILLISECONDS);
            return stsToken;
        } catch (ParseException e) {
            logger.error(e.getMessage());
        }
        return null;
    }

    /**
     * 获取短信服务管理凭证
     * @return
     */
    public StsToken getSmsStsToken(){
        try {
            StsRole stsRole = StsRole.getSmsManageRole();
            //从缓存中获取ststoken
            String stsJson = stringRedisTemplate.opsForValue().get("sms_sts:"+stsRole.getRoleSessionName());
            if(stsJson != null){
                return JSON.parseObject(stsJson, new TypeReference<StsToken>() {});
            }

            StsToken stsToken = getStsToken(stsRole);

            //设置到缓存中，并设置过期时间
            String expiration = stsToken.getExpiration();
            expiration = expiration.replace("Z"," UTC");
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss Z");
            Date expirationDate = format.parse(expiration);
            long expiredTime = expirationDate.getTime() - System.currentTimeMillis() - 1000;
            stringRedisTemplate.opsForValue().set("sms_sts:"+stsRole.getRoleSessionName(),
                    JSON.toJSONString(stsToken), expiredTime, TimeUnit.MILLISECONDS);
            return stsToken;
        } catch (ParseException e) {
            logger.error(e.getMessage());
        }
        return null;
    }
}
